﻿#if NETFRAMEWORK
using CookComputing.XmlRpc;
#else
using Horizon.XmlRpc.Client;
using Horizon.XmlRpc.Core;
#endif
using System;
using System.Collections.Generic;
using System.Linq;

namespace RosSharp.ParamServer
{
    /// <summary>
    ///   XML-RPC Client for ParameterServer API
    /// </summary>
    public sealed class ParameterServerClient
    {
        private ParameterServerProxy _proxy;

        public ParameterServerClient()
        {
            _proxy = XmlRpcProxyGen.Create<ParameterServerProxy>();
            _proxy.Url = ROS.ROS_MASTER_URI;
            _proxy.Timeout = 5000;
        }

        /// <summary>
        ///   Delete parameter
        /// </summary>
        /// <param name="callerId"> ROS caller ID </param>
        /// <param name="key"> Parameter name. </param>
        /// <returns> ignore </returns>
        public bool DeleteParam(string callerId, string key)
        {
            object[] Result = _proxy.DeleteParam(callerId, key);
            return (StatusCode)Result[0] == StatusCode.Success;
        }

        /// <summary>
        ///   Set parameter.
        /// </summary>
        /// <param name="callerId"> ROS caller ID </param>
        /// <param name="key"> Parameter name. </param>
        /// <param name="value"> Parameter value. </param>
        /// <returns> ignore </returns>
        public bool SetParam(string callerId, string key, object value)
        {
            object[] Result = _proxy.SetParam(callerId, key, value);
            if ((StatusCode)Result[0] == StatusCode.Success)
                return true;
            return false;
        }

        /// <summary>
        ///   Retrieve parameter value from server.
        /// </summary>
        /// <param name="callerId"> ROS caller ID </param>
        /// <param name="key"> Parameter name. If key is a namespace, getParam() will return a parameter tree. </param>
        /// <returns> parameterValue </returns>
        public object GetParam(string callerId, string key)
        {
            object[] Result = _proxy.GetParam(callerId, key);
            if ((StatusCode)Result[0] != StatusCode.Success)
                throw new InvalidOperationException((string)Result[1]);
            return Result[2];
        }

        /// <summary>
        ///   Search for parameter key on the Parameter Server.
        /// </summary>
        /// <param name="callerId"> ROS caller ID </param>
        /// <param name="key"> Parameter name to search for. </param>
        /// <returns> foundKey </returns>
        public string SearchParam(string callerId, string key)
        {
            object[] Result = _proxy.SearchParam(callerId, key);

            if ((StatusCode)Result[0] != StatusCode.Success)
                throw new InvalidOperationException((string)Result[1]);
            return (string)Result[2];
        }

        /// <summary>
        ///   Retrieve parameter value from server and subscribe to updates to that param. See paramUpdate() in the Node API.
        /// </summary>
        /// <param name="callerId"> ROS caller ID. </param>
        /// <param name="callerApi"> Node API URI of subscriber for paramUpdate callbacks. </param>
        /// <param name="key"> Parameter name </param>
        /// <returns> parameterValue </returns>
        public object SubscribeParam(string callerId, string callerApi, string key)
        {
            object[] Result = _proxy.SubscribeParam(callerId, callerApi, key);
            if ((StatusCode)Result[0] != StatusCode.Success)
                throw new InvalidOperationException((string)Result[1]);
            return Result[2];
        }

        /// <summary>
        ///   Retrieve parameter value from server and subscribe to updates to that param. See paramUpdate() in the Node API.
        /// </summary>
        /// <param name="callerId"> ROS caller ID. </param>
        /// <param name="callerApi"> Node API URI of subscriber. </param>
        /// <param name="key"> Parameter name. </param>
        /// <returns> number of unsubscribed </returns>
        public int UnsubscribeParam(string callerId, string callerApi, string key)
        {
            object[] Result = _proxy.UnsubscribeParam(callerId, callerApi, key);
            if ((StatusCode)Result[0] != StatusCode.Success)
                throw new InvalidOperationException((string)Result[1]);
            return (int)Result[2];
        }

        /// <summary>
        ///   Check if parameter is stored on server.
        /// </summary>
        /// <param name="callerId"> ROS caller ID. </param>
        /// <param name="key"> Parameter name. </param>
        /// <returns> hasParam </returns>
        public bool HasParam(string callerId, string key)
        {
            object[] Result = _proxy.HasParam(callerId, key);
            if ((StatusCode)Result[0] != StatusCode.Success)
                throw new InvalidOperationException((string)Result[1]);
            return (bool)Result[2];
        }

        /// <summary>
        ///   Get list of all parameter names stored on this server.
        /// </summary>
        /// <param name="callerId"> ROS caller ID. </param>
        /// <returns> parameter name list </returns>
        public List<string> GetParamNames(string callerId)
        {
            object[] Result = _proxy.GetParamNames(callerId);
            if ((StatusCode)Result[0] != StatusCode.Success)
                throw new InvalidOperationException((string)Result[1]);
            return ((string[])Result[2]).ToList();
        }
    }
}
